﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="NGram.cs" company="Arizona State University">
//   Copyright (C) 2011-2012 Sukru Tikves and Arizona State University
//   
//   Released under Microsoft Public License (Ms-PL)
//   See http://cipsdata.codeplex.com/license for up to date license 
//   informaiton.
// </copyright>
// <summary>
//   The n-gram.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Cips.DataMining
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    /// <summary>
    /// The n-gram.
    /// </summary>
    public class NGram
    {
        /// <summary>
        /// The dictionary.
        /// </summary>
        readonly IGenericTermDictionary dictionary;

        /// <summary>
        /// The individual terms.
        /// </summary>
        readonly int[] terms;

        /// <summary>
        /// Initializes a new instance of the <see cref="NGram"/> class.
        /// </summary>
        /// <param name="terms">The terms.</param>
        /// <param name="dictionary">The dictionary.</param>
        public NGram(IEnumerable<int> terms, IGenericTermDictionary dictionary = null)
        {
            if (terms == null) 
                throw new ArgumentNullException("terms");

            this.dictionary = dictionary;
            this.terms = terms.ToArray();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="NGram"/> class.
        /// </summary>
        /// <param name="dictionary">The dictionary.</param>
        /// <param name="terms">The terms.</param>
        public NGram(IGenericTermDictionary dictionary = null, params int[] terms)
        {
            this.terms = terms.ToArray();
            this.dictionary = dictionary;
        }

        /// <summary>
        /// Gets the keyword with the specified index.
        /// </summary>
        /// <param name="index">
        /// The index.
        /// </param>
        /// <returns>
        /// The keyword.
        /// </returns>
        public int this[int index]
        {
            get { return terms[index]; }
        }

        /// <summary>
        /// Compares the n-gram with the <see cref="other"/> instance.
        /// </summary>
        /// <param name="other">The other n-gram.</param>
        /// <returns><c>true</c> if both n-grams are equal, <c>false</c> otherwise</returns>
        public bool Equals(NGram other)
        {
            if (ReferenceEquals(null, other))
                return false;

            if (ReferenceEquals(this, other)) 
                return true;

            if (dictionary != other.dictionary || terms.Length != other.terms.Length)
                return false;

            for (var i = 0; i < terms.Length; i++)
                if (terms[i] != other.terms[i])
                    return false;

            return true;
        }

        /// <summary>
        /// Determines whether the specified <see cref="System.Object"/> is equal to this instance.
        /// </summary>
        /// <param name="obj">The <see cref="System.Object"/> to compare with this instance.</param>
        /// <returns>
        ///   <c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.
        /// </returns>
        public override bool Equals(object obj)
        {
            return obj.GetType() == typeof(NGram) && Equals((NGram)obj);
        }

        /// <summary>
        /// Returns a hash code for this instance.
        /// </summary>
        /// <returns>
        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
        /// </returns>
        public override int GetHashCode()
        {
            var retval = 99;

            for (int i = 0; i < terms.Length; i++)
                retval = (retval << 10 | retval >> 22) ^ (terms[i] * 13);

            return retval;
        }

        /// <summary>
        /// Returns a <see cref="System.String"/> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String"/> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            if (dictionary == null)
                return string.Join(" ", terms);

            return string.Join(" ", terms.Select(t => dictionary[t]));
        }
    }
}
